package com.am.lottery.service

import com.am.lottery.db.Db
import com.am.lottery.db.schema.Lottery
import com.am.lottery.util.JsonUtils
import com.am.lottery.view.common.LoadingState
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.core.JsonToken
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import org.dromara.hutool.core.data.id.IdUtil
import org.ktorm.dsl.*
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.File
import java.io.FileWriter
import java.time.LocalDate

object LotteryService

private val logger: Logger = LoggerFactory.getLogger(LotteryService::class.java)

fun loadHistoryData(): Flow<LoadingState> = flow {
    val client = OkHttpClient()

    val database = Db.database
    val latest = database.from(Lottery)
        .select()
        .orderBy(Lottery.drawDate.desc())
        .limit(0, 1)
        .map { row -> Lottery.createEntity(row) }
        .firstOrNull()

    if (latest == null) {
        val pageSize = 100
        var request = Request.Builder()
            .url(getUrl(pageSize = pageSize))
            .build()

        var res = client.newCall(request)
            .execute()
            .use { response ->
                val responseData = response.body.string()

                logger.info(response.toString())
                logger.info(responseData)
                JsonUtils.objectMapper.readValue(responseData, ServerResponseData::class.java)
            }

        // Emit third loading state
        emit(LoadingState.Loading("共${res.value.pages}页数据"))
        logger.info("共${res.value.pages}页数据")

        val fileBuffer = FileWriter(File("D:\\lottery.txt"), true)
        val list = arrayListOf<Item>()

        fileBuffer.use {

            for (pageNo in 1 until res.value.pages + 1) {
                emit(LoadingState.Loading("第${pageNo}页加载开始！"))
                logger.info("第${pageNo}页加载开始！")
                request = Request.Builder()
                    .url(getUrl(pageNo, pageSize))
                    .build()
                res = client.newCall(request)
                    .execute()
                    .use { response ->
                        val responseData = response.body.string()

                        fileBuffer.appendLine(responseData)
                        logger.info(response.toString())
                        try {
                            JsonUtils.objectMapper.readValue(responseData, ServerResponseData::class.java)
                        } catch (e: Exception) {
                            logger.error(responseData)
                            throw e
                        }
                    }
                list.addAll(res.value.list)
                emit(LoadingState.Loading("第${pageNo}页加载完成！"))
                logger.info("第${pageNo}页加载完成！")
                // 延迟 1 秒
                delay(1000)
            }
            emit(LoadingState.Loading("所有历史数据加载完成"))
            logger.info("所有历史数据加载完成")
            // Finish loading and hide the dialog
            emit(LoadingState.Idle)
        }

        Db.database.useTransaction {
            Db.database.batchInsert(Lottery) {
                list.map { it2 ->
                    item {
                        set(it.id, IdUtil.getSnowflakeNextId())
                        set(it.drawNum, it2.drawNum)
                        set(it.drawResult, it2.drawResult)
                        set(it.unSortDrawResult, it2.unSortDrawResult)
                        set(it.drawDate, it2.drawDate)
                    }
                }
            }
        }
        emit(LoadingState.Loading("所有历史数据保存完成"))
        logger.info("所有历史数据保存完成！")
    } else {

    }
}
    .flowOn(Dispatchers.IO)

fun getUrl(
    pageNo: Int = 1,
    pageSize: Int = 10
): HttpUrl {
    return HttpUrl.Builder()
        .scheme("https")
        .host("webapi.sporttery.cn")
        .addPathSegment("gateway")
        .addPathSegment("lottery")
        .addPathSegment("getHistoryPageListV1.qry")
        .addQueryParameter("gameNo", "85")
        .addQueryParameter("provinceId", "0")
        .addQueryParameter("isVerify", "1")
        .addQueryParameter("pageSize", "$pageSize")
        .addQueryParameter("pageNo", "$pageNo")
        .build()
}

data class ServerResponseData(
    val errorCode: String,
    val errorMessage: String,
    val success: Boolean,
    val value: Value,
)

data class Value(
    val lastPoolDraw: Item,
    val list: List<Item>,
    val pageNo: Int,
    val pageSize: Int,
    val pages: Int,
    val total: Int
)

@JsonIgnoreProperties(ignoreUnknown = true)
data class Item(
    /**
     * 期号
     */
    @JsonProperty("lotteryDrawNum")
    val drawNum: String?,

    /**
     * 开奖结果，排序后
     */
    @JsonProperty("lotteryDrawResult")
    val drawResult: String?,

    /**
     * 开奖结果，未排序
     */
    @JsonDeserialize(using = EmptyArrayToEmptyStringJsonDeserializer::class)
    @JsonProperty("lotteryUnsortDrawresult")
    val unSortDrawResult: String?,

    /**
     * 开奖日期
     */
    @JsonProperty("lotteryDrawTime")
    val drawDate: LocalDate?
)

object EmptyArrayToEmptyStringJsonDeserializer : JsonDeserializer<String?>() {
    override fun deserialize(p: JsonParser, ctxt: DeserializationContext): String? {
        return if (p.isExpectedStartObjectToken) {
            p.nextToken()
            null
        } else if (p.hasToken(JsonToken.VALUE_STRING)) {
            p.text
        } else {
            p.text
        }
    }
}